package logic

import (
	"core/command"
	"core/component/logger"
	"core/component/router"
	"core/network"
	"runtime/debug"
	"sync"
	"time"
)

type Client struct {
	*network.NetConn
	userID       uint64 //玩家id
	remoteAddr   string
	router       *router.Router
	joinOnlineID string
	bindOnline   bool
	msgRegOnce   sync.Once // 代理消息注册一次

	z int
}

func (cli *Client) Init() {
	cli.router = router.NewRouter()
	cli.registerGatewayOnlineHandler()
}

// gatewayOnline消息注册
func (cli *Client) registerGatewayOnlineHandler() {
	cli.router.Register(uint16(command.Command_CSPlayerLogin_Gateway), cli.playerLoginHandler)
	//client主动退出游戏
	cli.router.Register(uint16(command.Command_CSPlayerLogout_Gateway), cli.playerLogoutHandler)
	//心跳包
	cli.router.Register(uint16(command.Command_CSHeartBeat_Gateway), cli.playerHeartBeat)
}

// sendMsg 异步发送数据包
func (cli *Client) sendMsg(cmd command.Command, msg interface{}) bool {
	return cli.AsyncSend(uint16(cmd), msg)
}

func (cli *Client) OnMessage(data []byte) {
	defer func() {
		if err := recover(); err != nil {
			logger.Error("[server_client] panic ", err, "\n", string(debug.Stack()))
		}
	}()
	now := time.Now()
	msgID, err := cli.router.Route(data)
	if err != nil {
		_, err = cli.router.ForwardRoute(cli.joinOnlineID, cli.userID, data)
	}
	if command.Command(msgID).String() != "CSHeartBeat_Gateway" {
		logger.Debugf("[gateway] 已处理玩家:%v 消息ID::%v execTime:%v,addr:%v", cli.userID, command.Command(msgID).String(), time.Since(now), cli.remoteAddr)
	}
}

func (cli *Client) OnClose() {
	if cli.userID != 0 {
		clientManagerGetMe().removeClient(cli.ConnID)
		clientManagerGetMe().unbindUserID2Client(cli.userID)
	}
	if cli.joinOnlineID != "" {
		msgSend := &command.ClientOutOnline{
			PlayerId: cli.userID,
		}
		onlineServerMgrGetMe().sendMsgToOnlineServer(cli.joinOnlineID, command.Command_ClientOutOnline_Online, msgSend)
	}
	logger.Infof("[连接] 客户端连接断开 local:%v remote:%v userID:%v connID:%v", cli.LocalAddr(),
		cli.RemoteAddr(), cli.userID, cli.ConnID)
}

func (cli *Client) Marshal(msgID uint16, msg interface{}) ([]byte, error) {
	return cli.router.Marshal(msgID, msg)
}

func (cli *Client) OnConnect() {
	clientManagerGetMe().addClient(cli.ConnID, cli)
	logger.Infof("[连接] 建立连接 local:%s remote:%s connID:%v", cli.LocalAddr(), cli.RemoteAddr(), cli.ConnID)
	cli.remoteAddr = cli.RemoteAddr().String()
}

// 用户通过验证
func (c *Client) onUserVerify(userID uint64) {
	c.userID = userID
	clientManagerGetMe().bindUserID2Client(userID, c)
}

func (c *Client) clientLogout() {
	mSend := &command.SCPlayerLogoutRet{}
	clientManagerGetMe().removeClient(c.ConnID)
	clientManagerGetMe().unbindUserID2Client(c.userID)
	// 发送最后一个消息
	c.sendLastMsg(command.Command_SCPlayerLogoutRet_Gateway, mSend)
	logger.Infof("玩家%v 登出gateway", c.userID)
}

// sendLastMsg 发送最后一个消息 发送会关闭tcp连接 终止tcp goroutine
func (c *Client) sendLastMsg(cmd command.Command, msg interface{}) bool {
	return c.AsyncSendLastPacket(uint16(cmd), msg)
}

func (c *Client) sendClientOnlineMsg(onlineID string, isNew, isVisitor bool) {
	msgSend := &command.ClientInOnline{
		PlayerId:    c.userID,
		IsNewPlayer: isNew,
		IsVisitor:   isVisitor,
		GatewayIp:   ServerInstance().tcpAddr,
		RemoteAddr:  c.remoteAddr,
	}
	onlineServerMgrGetMe().sendMsgToOnlineServer(onlineID, command.Command_ClientInOnline_Online, msgSend)
	logger.Infof("玩家%v 登录到onlineServer %v", c.userID, onlineID)
}

// 注册代理转发消息处理器
func (c *Client) registerForwardMsgHandler(msgID uint16, handler router.ForwardMsghandler) {
	c.router.RegisterForwardHandler(msgID, handler)
}
